<?php
/**
 * Parcl
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://parcl.com/license
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@parcl.com so we can send you a copy immediately.
 *
 * @category parcl
 * @package parcl-core
 * @copyright Copyright (c) 2006-2011 Mikael Knutsson (http://mikn.me)
 * @license http://parcl.com/license New BSD License
 * 
 * @author mikael
 */

namespace Parcl\Core {

	if(PARCL_EXEC !== 1) {
		die('<h1>Incorrect Access</h1>You cannot access this file directly.<br/>' .
			 'If you got this error message by clicking a link on the site,' .
			 'please notify the webmaster as soon as possible.');
	}

	/**
	 * Purpose     : Collect all the Event Handlers in the same place to easily check on them.
	 * Description : This class contains all EventHandlers and was made a singleton
					 to avoid any duplication of it.
	 * - Construct -
	 * Input       : None.
	 * Output      : Not applicable.
	 * Description : Makes the class variable $handlers into an ArrayObject.
	 * Errors      : None.
	 * Assumptions : None.
	 * Dev Notes   : None at the moment.
	 */

	class EventHandlerCollection implements ISingleton {
		private $expiredEvents = array();
		private $handlers = null;
		private static $instance = null;

		public static function GetInstance() {
			if(is_null(self::$instance)) {
				self::$instance = new EventHandlerCollection();
			}
			return self::$instance;
		}

		private function __construct() {
			$this->handlers = new ArrayObject();
		}

		/**
		 * Input       : $handler: An event handler to add to the collection.
		 * Output      : None.
		 * Description : This function adds an EventHandler to the collection if it
						 is an instance of the class EventHandler.
		 * Errors      : An error is thrown if $handler isn't an EventHandler.
		 * Assumptions : None.
		 * Dev Notes   : Pretty straight-forward function.
		 */

		public function Add($handler) {
			EventHandler::IsEventHandler($handler);
			if(!$this->Contains($handler)) {
				$this->handlers->Append($handler);
			}
			else {
				throw new EventException('Tried adding the same event handler twice. EventHandler: '
										  . print_r($handler, true), EventException::EVENT );
			}
		}

		/**
		 * Input       : $event: The event being triggered.
						 $sender: The instance of the triggering class.
						 $args: Array of arguments to be passed to the callback of the
						 event handler.
		 * Output      : No direct output.
		 * Description : This function triggers the event and executes the callback
						 associated with it, then adds the event triggered to an array
						 of expired events.
		 * Errors      : Throws an error if you try to trigger an Event that hasn't
						 been registered in the EventCollection yet.
		 * Assumptions : None.
		 * Dev Notes   : Another straight-forward function.
		 */

		public function RaiseEvent($event, $sender, array $args) {
			$events = EventCollection::GetInstance();
			if($event != 'L:MESSAGE_RECEIVED') {
				watchdog::Log('Raising %event.', LogLevel::DEBUG, array('%event' => $event));
			}
			if(!$events->Contains(new Event($event))) {
				throw new EventException('Tried to trigger unregistered event "' .
										  $event . '".', EventException::EVENT);
			}
			foreach($this->handlers as $handler) {
				if($handler->GetEventName() == $event) {
					$handler->Raise($sender, $args);
				}
			}
			$events->SetFlagTriggered(new Event($event));
			return true;
		}

		/**
		 * Input       : $resetEvents: The events to remove the handlers from.
		 * Output      : Returns boolean true if completed successfully.
		 * Description : Resets the event handlers for the events given.
		 * Errors      : Throws a notice level error if it can't find any handlers.
		 * Assumptions : None.
		 * Dev Notes   : Resets the handlers. Added the $found variable to make error
						 throwing easier. I had to move the unset operation out from
						 the original foreach loop to avoid getting Notice level PHP
						 errors thrown at me.
		 */

		public function ResetHandlers(array $resetEvents) {
			$found = false;
			$Resettables = array();

			foreach($this->handlers as $k => $handler) {
				if(in_array(new Event($handler->GetEventName()), $resetEvents)) {
					$Resettables[] = $k;
					$found = true;
				}
			}
			foreach($Resettables as $reset) {
				$this->handlers->offsetUnset($reset);
			}
			if(!$found) {
				throw new EventException('No handlers registered to the events found.', EventException::NS_NOTICE);
			}
			return true;
		}

		public function Contains($handler) {
			EventHandler::IsEventHandler($handler);
			foreach($this->handlers as $eventHandler) {
				if($eventHandler == $handler) {
					return true;
				}
			}
			return false;
		}

	}
}